/*
 * cm_storage.c
 *
 *  Created on: 2014年7月22日
 *      Author: chens
 */

#include <string.h>
#include "cm_storage_def.h"

/* 各种类型的仓库初始化实现 */
extern void cmstorage_file_init(cm_storage **t);
extern void cmstorage_mem_init(cm_storage **t);

/*
 * @brief	创建一个仓库
 * @param	type：仓库类型，用文件或数据库
 * 		objsize：仓库中每个元素的大小
 * 		url：数据库文件路径 或 数据文件路径
 * 		serialize：仓库中所存数据使用的序列化方法
 * 		unserialize：仓库中所存数据所使用的反序列化方法
 * 		serialize和unserialize如果为NULL的话表示数据可以不做转换直接进行存储
 * @return	成功返回0 失败返回非0
 *
 */
cm_storage* cmstorage_create(enum CM_STORAGE_TYPE type, int objsize,
		const char *url, cm_serialize serialize,
		cm_unserialize unserialize)
{
	cm_storage *t = NULL;
	t = (cm_storage *) calloc(1, sizeof(cm_storage));
	if (t == NULL)
		return NULL;

	t->type = type;
	t->objsize = objsize;
	if (url != NULL)
		strncpy(t->url, url, LEN_MAX_FILE_NAME - 1);
	t->serialize = serialize;
	t->unserialize = unserialize;

	switch (type) {
	case CM_STORAGE_DB: // TODO 未实现
		free(t);
		t = NULL;
		break;
	case CM_STORAGE_FILE:
		cmstorage_file_init(&t);
		break;
	case CM_STORAGE_MEM:
		cmstorage_mem_init(&t);
		break;
	default:
		break;
	}
	return t;
}

extern void cmstorage_file_close(cm_storage **t);
extern void cmstorage_mem_close(cm_storage **t);
/*
 * @brief	关闭一个仓库
 * @param	指向仓库对象指针的指针
 * @return	*t所指向的仓库被关闭且 *t的值置为NULL
 */
void cmstorage_close(cm_storage **t)
{
	if (t == NULL || *t == NULL)
		return;

	switch ((*t)->type) {
	case CM_STORAGE_FILE:
		cmstorage_file_close(t);
		break;
	case CM_STORAGE_MEM:
		cmstorage_mem_close(t);
		break;
	case CM_STORAGE_DB:
		break;
	default:
		break;
	}

	free(*t);
	*t = NULL;
}

/* 各种类型的仓库存放数据的实现 */
extern int cmstorage_file_put(const cm_storage *t,
		const struct cmstorage_head *head, const char *data);
extern int cmstorage_mem_put(const cm_storage *t,
		const struct cmstorage_head *head, const char *data);

/*
 * @brief	将数据放入仓库
 * @param	t: 是一个指向仓库对象的指针
 * 		data: 指向要放入仓库的数据
 * 		state: 放入对象的状态
 * @return	0表示成功，非0表示失败
 */
int cmstorage_put(const cm_storage *t, void *data, enum CM_STORAGE_STATE state)
{
	char *temp = (char *) data;

	if (t->serialize != NULL) {	// 如果要进行序列化，则将开辟堆内存
		temp = (char *) calloc(1, t->objsize);
		if (temp == NULL)
			return -1;

		size_t retsize = t->objsize;
		if (0 != t->serialize(data, temp, &retsize)) {
			free(temp);
			return -1;
		}
	}

	struct cmstorage_head head;
	head.valid = 1;
	gettimeofday(&(head.create_time), NULL);
	gettimeofday(&(head.state_change), NULL);
	head.state = state;

	int ret = -1;
	switch (t->type) {
	case CM_STORAGE_DB:
		break;
	case CM_STORAGE_FILE:
		ret = cmstorage_file_put(t, &head, temp);
		break;
	case CM_STORAGE_MEM:
		ret = cmstorage_mem_put(t, &head, temp);
		break;
	default:
		break;
	}
	if (temp != (char *) data)
		free(temp);
	return ret;
}

/* 各种类型的仓库取数据的实现 */
// TODO 现在的取数据全部是顺序遍历，只适用于数据量很小或者按顺序存取的情况

extern int cmstorage_file_get(const cm_storage *t, enum CM_STORAGE_SORT sort,
		cm_satisfy cond, char *data, struct cmstorage_head* head);
extern int cmstorage_mem_get(const cm_storage *t, enum CM_STORAGE_SORT sort,
		cm_satisfy cond, char *data, struct cmstorage_head* head);

/*
 * @brief	将一条数据从仓库中取出，数据格式使用仓库的unserialize函数解析
 * @param	t: 仓库对象
 * 		sort：取数据时采用的排序方式
 * 		cond：用来比较是否满足条件
 * 		data与size指定用来存放数据的空间及空间大小
 * 		head：用来存放数据的额外信息，可以传递NULL
 * @return	成功则返回一个非负（可为0）的数据ID，失败返回-1
 */
int cmstorage_get(const cm_storage *t, enum CM_STORAGE_SORT sort,
		cm_satisfy cond, char *data, size_t size,
		struct cmstorage_head* head)
{
	int ret = -1;
	char *temp = (char *) data;
	if (t->unserialize != NULL) {	// 如果需要反序列化，则分配内存
		temp = (char *) calloc(1, t->objsize);
		if (temp == NULL)
			return -1;
	}
	// 根据仓库类型，从仓库中取出固定大小的数据(objsize)，如果不需要反序列化则数据直接放入data
	switch (t->type) {
	case CM_STORAGE_DB:
		break;
	case CM_STORAGE_FILE:
		ret = cmstorage_file_get(t, sort, cond, temp, head);
		break;
	case CM_STORAGE_MEM:
		ret = cmstorage_mem_get(t, sort, cond, temp, head);
		break;
	default:
		break;
	}

	if (ret >= 0) {
		if (t->unserialize != NULL)
			ret = t->unserialize(temp, data, &size);
	}
	if (temp != data)
		free(temp);
	return ret;
}
